#ifndef __HEAD_H__
#define __HEAD_H__

#include <my_header.h>

//时间轮片
#define WHEELMAX 300     // 时间轮片次数
#define MAX_SET_SIZE 1024  // 定义集合最大大小
#define MAX_ELEMENTS 4096  // 定义最大元素数


#include <openssl/md5.h>
#define MYSQL_ERROR_CHECK(ret, target, mysql, msg) \
    do { \
        if( (ret) != (target)) { \
            fprintf(stderr, "%s:%s\n", msg, mysql_error(mysql)); \
        }\
    } while(0)

typedef enum
{
    USER_REGI,
    USER_LOGIN,
    USER_LOGIN2,
    L_R_SUCCESS,
    L_R_ERR,
    

    C_OP_CD,
    CD_SUCCESS,
  

    C_OP_LS,
    LS_SUCCESS,


    C_OP_RMDIR,
    RMDIR_SUCCESS,


    C_OP_MKDIR,
    MKDIR_SUCCESS,

    C_OP_REMOVE,
    REMOVE_SUCCESS,

    DIR_ERR,

    C_OP_PUTS_QUERY,
    RES_PUTS_COMFIRM,
    C_OP_PUTS_BEGIN,

    C_OP_GETS_QUERY,
    RES_GETS_COMFIRM,
    C_OP_GETS_BEGIN
}MSG_TYPE;

typedef enum
{
    is_Dir,
    is_File
} file_dir_type;

typedef struct
{
    MSG_TYPE type;
    int args_len;
    char args_val[1024];
}RequestPackage;

typedef struct
{
    MSG_TYPE type;
    int args_len;
    char args_val[1024];
}ResponsePackage;

typedef struct taskNode_s {
    int netfd;
    int user_id;
    int now_path_id;
    MSG_TYPE type;
    char args[1024]; // 文件名或者目录名
    struct taskNode_s *pNext;
} taskNode_t;

typedef struct
{
    taskNode_t *pFront;
    taskNode_t *pRear;
    int queuesize;
} taskQueue_t;

typedef struct pthread_data_s {
    pthread_t *ptidarr;
    int workernum;
} pthread_data_t;
 
typedef struct client_info_s
{
    int now_path_id;
    int belongs_to_userid;
} Client_info;

// 服务端的共享资源
typedef struct 
{
    pthread_data_t  *pthread_data;
    Client_info *pclient_info;          // 每次新建连接之后需要更新client_info 
    int *exitflag;  // 退出标志位
    pthread_mutex_t *mutex_client_info;  // 用于client_info

    pthread_mutex_t *mysql_mutex;

    int *epfd;

    taskQueue_t *taskqueue;

    pthread_mutex_t *mutex_taskqueue;    // 用于任务队列的修改
    pthread_cond_t *cond;                // 用于taskqueue的主仆线程同步 
} shareRes_t;

//时间轮片

typedef struct SET{
    int idx;
    int arr[MAX_SET_SIZE];
}SET_t;

typedef struct TimeWheel{
    SET_t* wheel[WHEELMAX];
    int isalive[MAX_ELEMENTS];
    int count;
}TimeWheel_t;

typedef enum {
    _LOG_INFO,      // 表示命令操作成功，或者是一条调试信息
    _LOG_ERR        // 表示命令操作错误，需要记录具体的错误信息
} LOG_LEVEL;

int mysql_log(MYSQL *mysql, int user_id, int now_path_id, 
    const char *op, const char * args, const char *info, LOG_LEVEL level);

/**
 * @param
 * user_id & now_path_id: 对应client_info中的user_id与now_path_id
 * args: 传入的命令中的参数路径
 * args_len：参数路径的长度
 * presponse：待传的回复包的指针
 * truepath: 是保存得到的最后真实路径
 * netfd: 通信netfd
 * 返回值是-1说明彻底错误，调用者直接return -1就好，返回值是0，可以下面的逻辑
 */
int getTruePath(int user_id, int now_path_id, char *args, int args_len, MYSQL *mysql, 
        ResponsePackage *presponse, char *truepath, int netfd);


// server_api.c
int server_cd(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_ls(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
 /* int server_pwd(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id); */
int server_mkdir(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_rmdir(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int split_path(const char *input, char **out_parent, char **out_name);

int server_rmfile(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_puts_query(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_puts_begin(MYSQL *mysql, int *epfd, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_gets_query(MYSQL *mysql, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);
int server_gets_begin(MYSQL *mysql, int *epfd, int args_len, char *args, int netfd, Client_info *pclient_info, pthread_mutex_t *mutex, int now_path_id, int user_id);

//服务端解析器
// int resolver(RequestPackage *prequest);

// 服务端函数
int epollAdd(int epfd, int addfd, int trigger);
int epollDel(int epfd, int delfd);

// 初始化TCP连接
int initTcp(char *ip, char *port);

// 消息队列相关
int init_queue(taskQueue_t *queue);
int tail_insert(taskQueue_t *q, taskNode_t *new_node);
taskNode_t* head_delete(taskQueue_t *q);
taskNode_t *in_node(int netfd, int user_id, MSG_TYPE type, char *args, int args_len, int now_path_id);
void print_node(taskNode_t *go);

// 创建与初始化子线程
int init_pthread_data(pthread_data_t *pthread_data, int pthread_num);
int makeworker(shareRes_t *share, pthread_data_t *pthread_data, Client_info *clientInfo, int *exitFlag, pthread_mutex_t *mutex_client_info, pthread_mutex_t *mysql_mutex, pthread_mutex_t *long_queue_mutex,pthread_cond_t* long_queue_cond, pthread_mutex_t *short_queue_mutex,pthread_cond_t*short_queue_cond,taskQueue_t *queue_arr, int *epfd);
// 子线程入口与工作函数
void *pthread_enter(void *arg);
int pthread_func(taskNode_t*node,pthread_mutex_t* mtx_clientInfo,MYSQL *mysql,int *epfd,Client_info* client_info);

// 用户登录相关
int user_registration(MYSQL *mysql, const char *name, const char *setting, const char *ciphertest, int *user_path_id, int *user_id);
int user_login1(MYSQL *mysql, const char *name,char *setting);
int user_login2(MYSQL *mysql, const char *name,const char *ciphertest, int *user_path_id, int *user_id);

// recv返回值检测函数
int recvn(int netfd, void *buf, long len, long *pProcessed);
int ErrCheck_ClientClose(int ret, int netfd, int epfd, pthread_mutex_t *mtx, Client_info *clientInfo);

//时间轮片相关内容
int set_insert(SET_t* set,int x);
int set_delete(SET_t* set,int x);
void print_set(SET_t* set); // 打印集合内容
void print_set_content(SET_t* set, const char* prefix); // 打印集合内容 prefix是字符串，在printf中使用。
                                                        // print_set_content(replaced, "被替换的集合");
TimeWheel_t* TimeWheel_create();
int TimeWheel_upwheel(TimeWheel_t* timewheel, int index, int value);
SET_t* TimeWheel_insert(TimeWheel_t* timewheel,SET_t* set);
void TimeWheel_destroy(TimeWheel_t* timewheel);
int TimeWheel_deletefd(TimeWheel_t* timewheel,int x);
// 打印时间轮当前状态
void print_wheel_state(TimeWheel_t* tw);


extern char *serverDir;

#endif
